﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;

namespace WinScanInputSimulate
{

    /// <summary>
    /// 信捷PLC,使用原生写法进行TCP通信
    /// 通讯指令部分原生写
    /// </summary>
    public class PlcTcpIpHelper  
    {

        /// <summary>
        /// 与下位机Plc进行通信端 （Socket）
        /// </summary>
        private Socket tcpclient;

         
        public int PlcServerPort { get; set; }
        public string PlcServerIp { get; set; }

        public bool IsConnected { set; get; }
         
        public PlcTcpIpHelper(string ip, int port)
        {
            Connect(ip, port);
        }


        /// <summary>
        /// Socket 通信
        /// </summary>
        /// <param name="ip">IP</param>
        /// <param name="port">端口</param>
        /// <returns></returns>
        public bool Connect(string ip, int port)
        {
            if (string.IsNullOrEmpty(ip) || port < 1)
            { 
                return false;
            }

            PlcServerIp = ip;
            PlcServerPort = port;
              
            IPEndPoint ie = new IPEndPoint(IPAddress.Parse(ip), port);
            tcpclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
             
            try
            { 
                tcpclient.Connect(ie);
            }
            catch (SocketException ex)
            {
                IsConnected = false;
                return false;
            }
            IsConnected = true;
            return true;
        }
         
        /// <summary>
        /// 读取Plc一个数据信息以检测是否通信正常
        /// </summary>
        /// <param name="iAddress">默认使用：IniFileInfo.ChannelRegAddress</param>
        /// <returns></returns>
        public bool PlcChecketStatus(int iAddress)
        {
            byte[] array = null;
             
            if (tcpclient == null)
            {
                PlcReConnect();
            }
            try
            {
                array = ReadKeepReg(iAddress, 2);
            }
            catch (Exception ex)
            {
                LogHelper.Error("Plc重新连接", ex);
                array = null;
            }
            IsConnected = array != null;
            return IsConnected;
        }


        /// <summary>
		/// Plc重新连接
		/// </summary>
		/// <returns></returns>
		public bool PlcReConnect()
        {
            try
            {
                Connect(PlcServerIp, PlcServerPort);
            }
            catch (Exception ex)
            {
                LogHelper.Error("Plc重新连接", ex);
                IsConnected = false;
            }
            return IsConnected;
        }


        /// <summary>
        /// 读取Plc地址内容
        /// </summary>
        /// <param name="iAddress">地址</param>
        /// <param name="iLength">读取长度</param>
        /// <returns></returns>
        private byte[] ReadKeepReg(int iAddress, int iLength)
        {
            byte[] Result = null;
            if (tcpclient == null) return null;
              
            if (iAddress < 0 || IsConnected == false) return null;

            try
            {
                ByteArray byteArray = new ByteArray(12);
                byteArray.Add(new byte[8] { 0, 0, 0, 0, 0, 6, 1, 3 });  //功能码
                byteArray.Add((byte)((iAddress - iAddress % 256) / 256));//起始数据地址
                byteArray.Add((byte)(iAddress % 256));
                byteArray.Add((byte)((iLength - iLength % 256) / 256));
                byteArray.Add((byte)(iLength % 256));
                tcpclient.Send(byteArray.array, byteArray.array.Length, SocketFlags.None);
                byte[] data = new byte[512];
                tcpclient.Receive(data, 512, SocketFlags.None);
                int length = iLength * 2;
                if (length == data[8])
                {
                    Result = ByteMsgToRes(data, 9, length);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error($"Plc.ReadKeepReg 失败 addr:{iAddress}  iLength:{iLength}", ex);
            }
            return Result;
        }


        /// <summary>
        /// 字节数组返回处理
        /// </summary>
        /// <param name="MsgByte">消息字节</param>
        /// <param name="Start">开始位</param>
        /// <param name="Length">长度</param>
        /// <returns></returns>
        private byte[] ByteMsgToRes(byte[] MsgByte, int Start, int Length)
        {
            byte[] Result = null;
            if (MsgByte != null && MsgByte.Length != 0)
            { //有值
                Result = new byte[Length];//值的大小
                for (int i = 0; i < Length; i++)
                {
                    Result[i] = MsgByte[i + Start];
                }
            }
            return Result;
        }



    }


    public class ByteArray
    {
        private List<byte> list = new List<byte>();
        public byte[] array => list.ToArray();
        public ByteArray()
        {
            list = new List<byte>();
        }

        public ByteArray(int size)
        {
            list = new List<byte>(size);
        }

        public void Clear()
        {
            list = new List<byte>();
        }

        public void Add(byte item)
        {
            list.Add(item);
        }

        public void Add(byte[] items)
        {
            list.AddRange(items);
        }
    }

}
